package com.xinchuang.service.impl;

import cn.hutool.core.util.ObjectUtil;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.sun.org.apache.bcel.internal.generic.I2F;
import com.xinchuang.comment.R;
import com.xinchuang.common.Result;
import com.xinchuang.common.ResultUtil;
import com.xinchuang.entity.train.TrainAnswer;
import com.xinchuang.entity.train.TrainImg;
import com.xinchuang.entity.train.TrainRecord;
import com.xinchuang.service.ComparisonService;
import com.xinchuang.service.train.TrainAnswerService;
import com.xinchuang.service.train.TrainImgService;
import com.xinchuang.service.train.TrainRecordService;
import com.xinchuang.util.FileElseUtil;
import com.xinchuang.util.RedisUtil;
import io.swagger.models.auth.In;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.Date;
import java.text.SimpleDateFormat;
import java.util.List;

import com.xinchuang.utils.DateUtils;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import com.alibaba.fastjson.JSON;

import javax.servlet.http.HttpServletRequest;

@Service
public class ComparisonServiceImpl implements ComparisonService {

    private static DateTimeFormatter sdf = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");

    @Autowired
    private TrainImgService trainImgService;

    @Autowired
    private TrainRecordService trainRecordService;

    @Autowired
    private TrainAnswerService trainAnswerService;

    @Autowired
    private RedisUtil redisUtil;

    @Override
    public Result dataSave(JSONObject jsonObject) {
        //jsonobject解析获取试卷标识
        String testId = jsonObject.getString("testId");
        //jsonobject解析获取对错
        String answerFlag = jsonObject.getString("answerFlag");

        //从请求的头部获取userId
        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = attributes.getRequest();
        String userId = getUserId(request.getHeader("Id"));

        //考试记录
        if (!isTrain(userId)) {
            return ResultUtil.error(500, "当前考试已结束，请重新开始答题！");
        }

        answer(userId, testId, answerFlag);

        //答题总数
        String numKey = "train_total_" + userId;
        int count = FileElseUtil.getObjectToInt(redisUtil.get(numKey));
        int trueCount = 0;
        int answerCount = 0;
        if (count > 0) {
            String trainKey = "train_task_" + userId;
            List<Object> list = redisUtil.lGet(trainKey, 0, count - 1);
            String answerKey = "train_answer_" + userId;
            for (Object o : list) {
                String judge = FileElseUtil.getObjectToString(redisUtil.hget(answerKey, o.toString()));
                if ("1".equals(judge)) {
                    trueCount++;
                }
                if ("0".equals(judge) || "1".equals(judge)) {
                    answerCount++;
                }
                TrainRecord trainRecord = trainRecordService.getById(userId);
                trainRecord.setCorrectNum(trainRecord.getCorrectNum() + trueCount);
                trainRecord.setTitleNum(trainRecord.getTitleNum() + answerCount);
                trainRecordService.updateById(trainRecord);
            }
        }
        deleteTrain(userId);
        JSONObject resultJson = new JSONObject();
        resultJson.put("numberRight", trueCount);
        resultJson.put("numberTotal", count);
        resultJson.put("timeTotal", 0);
        return ResultUtil.success(resultJson);
    }

    @Override
    public String comparisonData() {
//        QueryWrapper<TrainImg> trainImgQueryWrapper = new QueryWrapper<>();
        int count = trainImgService.count();
        JSONObject trainJson = new JSONObject();
        trainJson.put("totalNumber", count);
        return JSON.toJSONString(R.data(trainJson));
    }

    @Override
    public Result nextData(JSONObject jsonObject) {
        //jsonobject解析获取类型
         Integer type = jsonObject.getInteger("type");
        //jsonobject解析获取试卷标识
        String testId = jsonObject.getString("testId");
        //jsonobject解析获取对错
        String answerFlag = jsonObject.getString("answerFlag");

        //从请求的头部获取userId
        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = attributes.getRequest();
        String userId = getUserId(request.getHeader("Id"));

        //考试记录
        if (!isTrain(userId)) {
            return ResultUtil.error(500, "当前考试已结束，请重新开始答题！");
        }

        if (type.intValue() == 0 || type.intValue() == 1) {
            //记录当前考试
            writeTrain(userId, testId, answerFlag);
            //下一题
            if (isNext(userId)) {
                return ResultUtil.error(500, "已经是最后一道题了");
            }
        } else {
            //记录当前考试
            readTrain(userId);
            if (isBack(userId)) {
                return ResultUtil.error(500, "已经是第一道题了");
            }
        }
        JSONObject img = getImg(userId, type.intValue());
        if (null == img) {
            return ResultUtil.error(500, "题目已被删除，无法进行答题");
        }
        return ResultUtil.success(img);
    }

    @Override
    public String savaData(JSONObject jsonObject) {
        //jsonobject解析获取标识
        String id = jsonObject.getString("id");
        //jsonobject解析获取标绘1
        String plotList1 = jsonObject.getString("plotList1");
        //jsonobject解析获取标绘2
        String plotList2 = jsonObject.getString("plotList2");
        //jsonobject解析获取试卷标识
        String testId = jsonObject.getString("testId");
        TrainImg trainImg = trainImgService.getById(testId);
        if (null == trainImg) {
            return JSON.toJSONString(R.success("无数据"));
        } else {
            JSONObject answerFlag = new JSONObject();
            if (plotList1.equals(trainImg.getImgPositionOne()) && plotList2.equals(trainImg.getImgPositionTwo())) {
                answerFlag.put("answerFlag", true);
            } else {
                answerFlag.put("answerFlag", false);
            }
            return JSON.toJSONString(R.data(answerFlag));
        }
    }

    @Override
    public Result startTest(JSONObject jsonObject, String id) {
        //jsonobject解析获取题号
        Integer number = jsonObject.getInteger("number");
        int total = trainImgService.count();
        if (null != number) {
            if (trainImgService.count() < Integer.valueOf(number).intValue()) {
                return ResultUtil.error(500, "开始答题提数，不能超过总提数，请重新选择");
            } else if (0 == total) {
                return ResultUtil.error(500, "题库为空，不可进行答题");
            }
        } else {
            return ResultUtil.error(500, "请输入正确的答题次数");
        }
        String userId = getUserId(id);
        //清空答题记录表
        trainAnswerService.lambdaUpdate().eq(TrainAnswer::getUserId, userId).remove();
        //记录答题内容
        TrainRecord trainRecord = trainRecordService.getById(userId);
        if (ObjectUtil.isNull(trainRecord)) {
            trainRecord = new TrainRecord();
            trainRecord.setId(userId);
            trainRecord.setUserId(userId);
            trainRecord.setCorrectNum(0);
            trainRecord.setTitleNum(0);
        }
        trainRecord.setTrainTime(new Date());
        trainRecordService.saveOrUpdate(trainRecord);
        //题库数据放入缓存
        List<TrainImg> trainImgs = trainImgService.lambdaQuery().orderByAsc(TrainImg::getSort).last("LIMIT " + (number - 1) + "," + total).list();
        //查询题号对应的题
        QueryWrapper<TrainImg> queryWrapper = new QueryWrapper<>();
        queryWrapper.orderByAsc("sort");
        queryWrapper.last("LIMIT " + (Integer.valueOf(number) - 1) + ",1");
        TrainImg trainImg = trainImgService.getOne(queryWrapper);
        JSONObject imgJson = new JSONObject();
        imgJson.put("id", trainRecord.getId());
        imgJson.put("imgName1", trainImg.getImgNameOne());
        imgJson.put("imgName2", trainImg.getImgNameTwo());
        imgJson.put("imgUrl1", trainImg.getImgUrlOne());
        imgJson.put("imgUrl2", trainImg.getImgUrlTwo());
        imgJson.put("plotList1", JSONArray.parseArray(trainImg.getImgPositionOne()));
        imgJson.put("plotList2", JSONArray.parseArray(trainImg.getImgPositionTwo()));
        imgJson.put("updateTime", sdf.format(trainImg.getUpdateTime()));
        imgJson.put("testId", trainImg.getId());
        //放入缓存
        trainImgToRedisList(userId, trainImgs);
        return ResultUtil.success(imgJson);
    }

    private void trainImgToRedisList(String userId, List<TrainImg> trainImgs) {
        String trainKey = "train_task_" + userId;
        String numKey = "train_total_" + userId;
        String signKey = "train_now_" + userId;
        deleteTrain(userId);
        List<Object> ids = new ArrayList<>();
        for (TrainImg img : trainImgs) {
            ids.add(img.getId());
        }
        redisUtil.lSet(trainKey, ids);
        redisUtil.set(numKey, 0);
        redisUtil.set(signKey, 0);
    }

    private void answer(String userId, String testId, String answerFlag) {
        String answerKey = "train_answer_" + userId;
        if (!redisUtil.hHasKey(answerKey, testId)) {
            String numKey = "train_total_" + userId;
            int anInt = FileElseUtil.getObjectToInt(redisUtil.get(numKey));
            anInt += 1;
            redisUtil.set(numKey, anInt);
        }
        if (StringUtils.isNotBlank(answerFlag)) {
            redisUtil.hset(answerKey, testId, "true".equals(answerFlag) ? "1" : "0");
        } else {
            redisUtil.hset(answerKey, testId, "2");
        }
    }

    private void writeTrain(String userId, String testId, String answerFlag) {
        String signKey = "train_now_" + userId;
        int toInt = FileElseUtil.getObjectToInt(redisUtil.get(signKey));
        if (toInt < 0) {
            toInt = 0;
        }
        String trainKey = "train_task_" + userId;
        long size = redisUtil.lGetListSize(trainKey);
        if (toInt < size) {
            toInt += 1;
        }
        redisUtil.set(signKey, toInt);
        answer(userId, testId, answerFlag);
    }

    private void readTrain(String userId) {
        String signKey = "train_now_" + userId;
        int toInt = FileElseUtil.getObjectToInt(redisUtil.get(signKey));
        String trainKey = "train_task_" + userId;
        long size = redisUtil.lGetListSize(trainKey);
        if (toInt == size) {
            toInt = Math.toIntExact(size - 1);
        }
        toInt -= 1;
        if (toInt < 0) {
            toInt = -1;
        }
        redisUtil.set(signKey, toInt);
    }

    private JSONObject getImg(String userId, int sign) {
        String signKey = "train_now_" + userId;
        String trainKey = "train_task_" + userId;
        String answerKey = "train_answer_" + userId;
        String numKey = "train_total_" + userId;
        if (!redisUtil.hasKey(trainKey)) {
            return null;
        }
        int toInt = FileElseUtil.getObjectToInt(redisUtil.get(signKey));
        if (toInt < 0) {
            toInt = 0;
            redisUtil.set(signKey, 0);
        }

        long size = redisUtil.lGetListSize(trainKey);
        if (toInt >= size) {
            toInt = sign - 1;
        }
        List<Object> list = redisUtil.lGet(trainKey, toInt, toInt);
        Object o = list.get(0);
        TrainImg trainImg = trainImgService.getById(o.toString());
        if (ObjectUtil.isNull(trainImg)) {
            redisUtil.lRemove(trainKey, toInt, o);
            if (redisUtil.hHasKey(answerKey, o.toString())) {
                int i = FileElseUtil.getObjectToInt(redisUtil.get(numKey));
                i -= 1;
                redisUtil.set(numKey, i);
            }
            if (sign == 2) {
                readTrain(userId);
            }
            return getImg(userId, sign);
        }
        JSONObject imgJson = new JSONObject();
        imgJson.put("imgName1", trainImg.getImgNameOne());
        imgJson.put("imgName2", trainImg.getImgNameTwo());
        imgJson.put("imgUrl1", trainImg.getImgUrlOne());
        imgJson.put("imgUrl2", trainImg.getImgUrlTwo());
        imgJson.put("plotList1", JSONArray.parseArray(trainImg.getImgPositionOne()));
        imgJson.put("plotList2", JSONArray.parseArray(trainImg.getImgPositionTwo()));
        imgJson.put("updateTime", sdf.format(trainImg.getUpdateTime()));
        imgJson.put("testId", trainImg.getId());
        return imgJson;
    }

    private boolean isBack(String userId) {
        String signKey = "train_now_" + userId;
        int toInt = FileElseUtil.getObjectToInt(redisUtil.get(signKey));
        if (toInt < 0) {
            return true;
        }
        return false;
    }

    private boolean isNext(String userId) {
        String signKey = "train_now_" + userId;
        String trainKey = "train_task_" + userId;
        int toInt = FileElseUtil.getObjectToInt(redisUtil.get(signKey));
        long size = redisUtil.lGetListSize(trainKey);
        if (toInt >= size) {
            return true;
        }
        return false;
    }

    private void deleteTrain(String userId) {
        String trainKey = "train_task_" + userId;
        String numKey = "train_total_" + userId;
        String answerKey = "train_answer_" + userId;
        String signKey = "train_now_" + userId;
        redisUtil.del(trainKey, numKey, answerKey, signKey);
    }

    private boolean isTrain(String userId) {
        String numKey = "train_total_" + userId;
        return redisUtil.hasKey(numKey);
    }

    private String getUserId(String id) {
        return redisUtil.get("USER_KUNMING_USERID_" + id).toString();
    }

}
